#include "rtc.h"
#include "delay.h"
#include "stm32f4xx_rtc.h" 

#include "stdio.h"

NVIC_InitTypeDef   NVIC_InitStructure;

typedef struct {
   RTC_DateTypeDef date;
   RTC_TimeTypeDef time;
}T_CalendarObj;

//RTC时间设置
//hour,min,sec:小时,分钟,秒钟
//ampm:@RTC_AM_PM_Definitions  :RTC_H12_AM/RTC_H12_PM
//返回值:SUCEE(1),成功
//       ERROR(0),进入初始化模式失败 
ErrorStatus RTC_Set_Time(uint8_t hour,uint8_t min,uint8_t sec,uint8_t ampm)
{
	RTC_TimeTypeDef RTC_TimeTypeInitStructure;
	
	RTC_TimeTypeInitStructure.RTC_Hours=hour;
	RTC_TimeTypeInitStructure.RTC_Minutes=min;
	RTC_TimeTypeInitStructure.RTC_Seconds=sec;
	RTC_TimeTypeInitStructure.RTC_H12=ampm;
	
	return RTC_SetTime(RTC_Format_BIN,&RTC_TimeTypeInitStructure);
	
}
//RTC日期设置
//year,month,date:年(0~99),月(1~12),日(0~31)
//week:星期(1~7,0,非法!)
//返回值:SUCEE(1),成功
//       ERROR(0),进入初始化模式失败 
ErrorStatus RTC_Set_Date(uint8_t year,uint8_t month,uint8_t date,uint8_t week)
{
	
	RTC_DateTypeDef RTC_DateTypeInitStructure;
	RTC_DateTypeInitStructure.RTC_Date=date;
	RTC_DateTypeInitStructure.RTC_Month=month;
	RTC_DateTypeInitStructure.RTC_WeekDay=week;
	RTC_DateTypeInitStructure.RTC_Year=year;
	return RTC_SetDate(RTC_Format_BIN,&RTC_DateTypeInitStructure);
}

//RTC初始化
//返回值:0,初始化成功;
//       1,LSE开启失败;
//       2,进入初始化模式失败;
uint8_t rtc_init(void)
{
	RTC_InitTypeDef RTC_InitStructure;
	uint16_t retry=0X1FFF; 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能PWR时钟
	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问 
	
	if(RTC_ReadBackupRegister(RTC_BKP_DR0)!=0x5050)		//是否第一次配置?
	{
		RCC_LSEConfig(RCC_LSE_ON);//LSE 开启    
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
        {
			retry++;
			delay_ms(10);
        }
		if(retry==0)
        {
            return 1;		//LSE 开启失败. 
        }
			
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
		RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟 

        RTC_InitStructure.RTC_AsynchPrediv = 0x7F;//RTC异步分频系数(1~0X7F)
        RTC_InitStructure.RTC_SynchPrediv  = 0xFF;//RTC同步分频系数(0~7FFF)
        RTC_InitStructure.RTC_HourFormat   = RTC_HourFormat_24;//RTC设置为,24小时格式
        RTC_Init(&RTC_InitStructure);
     
		//RTC_Set_Time(23,59,56,RTC_H12_AM);	//设置时间
		//RTC_Set_Date(14,5,5,1);		//设置日期
	 
		RTC_WriteBackupRegister(RTC_BKP_DR0,0x5050);	//标记已经初始化过了
	} 
 
	return 0;
}

uint8_t Is_Leap_Year(uint64_t year)
{			  
	if(year%4==0) 
	{ 
		if(year%100==0) 
		{ 
			if(year%400==0)return 1;	   
			else return 0;   
		}else return 1;   
	}else return 0;	
}
const uint8_t mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int64_t Rtc_GetCount(T_CalendarObj time)  
{
	uint64_t t;
    uint64_t seccount=0;
	if(time.date.RTC_Year+2000<1970||time.date.RTC_Year+2000>2099){
		return -1;	 
	}
	for(t=1970;t<time.date.RTC_Year+2000;t++)
	{
		if(Is_Leap_Year(t))seccount+=31622400;
		else seccount+=31536000;			  
	}
    time.date.RTC_Month-=1;
	for(t=0;t< time.date.RTC_Month;t++)	  
	{
		seccount+=(uint32_t)mon_table[t]*86400;
		if(Is_Leap_Year(time.date.RTC_Year+2000)&&t==1)seccount+=86400;
	}
	seccount+=(uint32_t)(time.date.RTC_Date-1)*86400;
	seccount+=(uint32_t)(time.time.RTC_Hours-8)*3600;
    seccount+=(uint32_t)time.time.RTC_Minutes*60;	
	seccount+=time.time.RTC_Seconds;
	return seccount;
}
uint8_t const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表	 
uint8_t RTC_Get_Week(uint16_t year,uint8_t month,uint8_t day)
{	
	uint16_t temp2;
	uint8_t yearH,yearL;
	
	yearH=year/100;	yearL=year%100; 
	// 如果为21世纪,年份数加100  
	if (yearH>19)yearL+=100;
	// 所过闰年数只算1900年之后的  
	temp2=yearL+yearL/4;
	temp2=temp2%7; 
	temp2=temp2+day+table_week[month-1];
	if (yearL%4==0&&month<3)temp2--;
	return(temp2%7);
}			
T_CalendarObj RTC_Get(uint64_t timeout)
{
  timeout = timeout/1000;
  T_CalendarObj calendar;
	uint64_t daycnt=0;
	
	uint64_t temp=0;
	uint64_t temp1=0;	  
  
 	temp=timeout/86400;   //得到天数(秒钟数对应的)
	if(daycnt!=temp)//超过一天了
	{	  
		daycnt=temp;
		temp1=1970;	//从1970年开始
		while(temp>=365)
		{				 
			if(Is_Leap_Year(temp1))//是闰年
			{
				if(temp>=366)temp-=366;//闰年的秒钟数
				else {temp1++;break;}  
			}
			else temp-=365;	  //平年 
			temp1++;  
		}   
		calendar.date.RTC_Year=temp1-2000;//得到年份
		temp1=0;
		while(temp>=28)//超过了一个月
		{
			if(Is_Leap_Year(calendar.date.RTC_Year+2000)&&temp1==1)//当年是不是闰年/2月份
			{
				if(temp>=29)temp-=29;//闰年的秒钟数
				else break; 
			}
			else 
			{
				if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
				else break;
			}
			temp1++;  
		}
		calendar.date.RTC_Month=temp1+1;	//得到月份
		calendar.date.RTC_Date=temp+1;  	//得到日期 
	}
	temp=timeout%86400;     		//得到秒钟数   	   
    
	calendar.time.RTC_Hours=(temp/3600+8)%24;     	//小时
	calendar.time.RTC_Minutes=(temp%3600)/60; 	//分钟	
	calendar.time.RTC_Seconds=(temp%3600)%60; 	//秒钟
	calendar.date.RTC_WeekDay=RTC_Get_Week(calendar.date.RTC_Year+2000,calendar.date.RTC_Month,calendar.date.RTC_Date);//获取星期   
	return calendar;
}	

//设置闹钟时间(按星期闹铃,24小时制)
//week:星期几(1~7) @ref  RTC_Alarm_Definitions
//hour,min,sec:小时,分钟,秒钟
void RTC_Set_AlarmA(uint8_t week,uint8_t hour,uint8_t min,uint8_t sec)
{ 
	EXTI_InitTypeDef   EXTI_InitStructure;
	RTC_AlarmTypeDef RTC_AlarmTypeInitStructure;
	RTC_TimeTypeDef RTC_TimeTypeInitStructure;
	
	RTC_AlarmCmd(RTC_Alarm_A,DISABLE);//关闭闹钟A 
	
  RTC_TimeTypeInitStructure.RTC_Hours=hour;//小时
	RTC_TimeTypeInitStructure.RTC_Minutes=min;//分钟
	RTC_TimeTypeInitStructure.RTC_Seconds=sec;//秒
	RTC_TimeTypeInitStructure.RTC_H12=RTC_H12_AM;
  
	RTC_AlarmTypeInitStructure.RTC_AlarmDateWeekDay=week;//星期
	RTC_AlarmTypeInitStructure.RTC_AlarmDateWeekDaySel=RTC_AlarmDateWeekDaySel_WeekDay;//按星期闹
	RTC_AlarmTypeInitStructure.RTC_AlarmMask=RTC_AlarmMask_None;//精确匹配星期，时分秒
	RTC_AlarmTypeInitStructure.RTC_AlarmTime=RTC_TimeTypeInitStructure;
  RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&RTC_AlarmTypeInitStructure);
 
	
	RTC_ClearITPendingBit(RTC_IT_ALRA);//清除RTC闹钟A的标志
  EXTI_ClearITPendingBit(EXTI_Line17);//清除LINE17上的中断标志位 
	
	RTC_ITConfig(RTC_IT_ALRA,ENABLE);//开启闹钟A中断
	RTC_AlarmCmd(RTC_Alarm_A,ENABLE);//开启闹钟A 
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line17;//LINE17
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE17
  EXTI_Init(&EXTI_InitStructure);//配置

	NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn; 
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);//配置
}

//周期性唤醒定时器设置  
/*wksel:  @ref RTC_Wakeup_Timer_Definitions
#define RTC_WakeUpClock_RTCCLK_Div16        ((uint32_t)0x00000000)
#define RTC_WakeUpClock_RTCCLK_Div8         ((uint32_t)0x00000001)
#define RTC_WakeUpClock_RTCCLK_Div4         ((uint32_t)0x00000002)
#define RTC_WakeUpClock_RTCCLK_Div2         ((uint32_t)0x00000003)
#define RTC_WakeUpClock_CK_SPRE_16bits      ((uint32_t)0x00000004)
#define RTC_WakeUpClock_CK_SPRE_17bits      ((uint32_t)0x00000006)
*/
//cnt:自动重装载值.减到0,产生中断.
void RTC_Set_WakeUp(uint32_t wksel,uint16_t cnt)
{ 
	EXTI_InitTypeDef   EXTI_InitStructure;
	
	RTC_WakeUpCmd(DISABLE);//关闭WAKE UP
	
	RTC_WakeUpClockConfig(wksel);//唤醒时钟选择
	
	RTC_SetWakeUpCounter(cnt);//设置WAKE UP自动重装载寄存器
	
	
	RTC_ClearITPendingBit(RTC_IT_WUT); //清除RTC WAKE UP的标志
  EXTI_ClearITPendingBit(EXTI_Line22);//清除LINE22上的中断标志位 
	 
	RTC_ITConfig(RTC_IT_WUT,ENABLE);//开启WAKE UP 定时器中断
	RTC_WakeUpCmd( ENABLE);//开启WAKE UP 定时器　
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line22;//LINE22
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE22
  EXTI_Init(&EXTI_InitStructure);//配置
 
 
	NVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn; 
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);//配置
}

//RTC闹钟中断服务函数
void RTC_Alarm_IRQHandler(void)
{    
	if(RTC_GetFlagStatus(RTC_FLAG_ALRAF)==SET)//ALARM A中断?
	{
		RTC_ClearFlag(RTC_FLAG_ALRAF);//清除中断标志
	}   
	EXTI_ClearITPendingBit(EXTI_Line17);	//清除中断线17的中断标志 											 
}

//RTC WAKE UP中断服务函数
void RTC_WKUP_IRQHandler(void)
{    
	if(RTC_GetFlagStatus(RTC_FLAG_WUTF)==SET)//WK_UP中断?
	{ 
		RTC_ClearFlag(RTC_FLAG_WUTF);	//清除中断标志
	}   
	EXTI_ClearITPendingBit(EXTI_Line22);//清除中断线22的中断标志 								
}
 
ErrorStatus RTC_GetTimeNow(T_CalendarObj *obj)
{
    RTC_GetTime(RTC_Format_BIN, &obj->time);

    RTC_GetDate(RTC_Format_BIN, &obj->date);
    return SUCCESS;
}

void rtc_get_current_time(T_TimeFmt *tim){
	T_CalendarObj obj;
    RTC_GetTimeNow(&obj);
    tim->year = obj.date.RTC_Year;
    tim->month = obj.date.RTC_Month;
	  tim->week = obj.date.RTC_WeekDay;
    tim->date =  obj.date.RTC_Date;
    tim->hour = obj.time.RTC_Hours;
    tim->min = obj.time.RTC_Minutes;
    tim->sec = obj.time.RTC_Seconds;
}

int rtc_get_currt_time_sec(void){
	T_CalendarObj obj;
    RTC_GetTimeNow(&obj);

    return Rtc_GetCount(obj);
}

uint32_t rtc_get_currt_hour(void){
    T_TimeFmt tim;
    rtc_get_current_time(&tim);    
    return tim.hour;
}

uint32_t rtc_get_currt_minute(void){
    T_TimeFmt tim;
    rtc_get_current_time(&tim);
    return tim.min;
}

void rtc_get_currt_time_str(char_t *time, int32_t len){
    T_TimeFmt tim;
    rtc_get_current_time(&tim);
    snprintf(time, len, "%4d%02d%02d%02d%02d%02d", tim.year+2000, tim.month,tim.date,tim.hour,tim.min,tim.sec);
}

void rtc_get_currt_time_format(char_t *time, int32_t len){
    T_TimeFmt tim;
    rtc_get_current_time(&tim);
    snprintf(time, len, "%4d-%02d-%02d %02d:%02d:%02d", tim.year+2000, tim.month,tim.date,tim.hour,tim.min,tim.sec);
}

void RTC_GetTimeFmtStr(T_TimeFmt * tim, char *str){
	
}

unsigned int RTC_GetTimeFmtSec(T_TimeFmt *tim){
	
	  T_CalendarObj obj;
   
	  obj.date.RTC_Year = tim->year;
	  obj.date.RTC_Month = tim->month;
	  obj.date.RTC_Date = tim->date;
  	obj.date.RTC_WeekDay = tim->week;
  	obj.time.RTC_Hours = tim->hour;
  	obj.time.RTC_Minutes = tim->min;
	  obj.time.RTC_Seconds = tim->sec;

    return Rtc_GetCount(obj);
}

void GetTimeStrFromSec(unsigned int sec, char *str){
	
}

int rtc_set_time(int year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec,uint8_t week){

    if(RTC_Set_Date(year-2000, mon, day, week) != SUCCESS){
        return -1;
    }
    if (RTC_Set_Time(hour, min, sec, RTC_H12_PM) != SUCCESS){
        return -1;
    }
    return 0;
}

int rtc_set_time_by_sec(uint64_t sec){
    T_CalendarObj obj = RTC_Get(sec);
    printf("time: %d-%d-%d %d:%d:%d\r\n", obj.date.RTC_Year, obj.date.RTC_Month, obj.date.RTC_Date, 
                        obj.time.RTC_Hours, obj.time.RTC_Minutes, obj.time.RTC_Seconds);
    return rtc_set_time(obj.date.RTC_Year+2000, obj.date.RTC_Month, obj.date.RTC_Date, 
                        obj.time.RTC_Hours, obj.time.RTC_Minutes, obj.time.RTC_Seconds,1);
}






